package com.uuticketweb.ticket.flight.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

import com.uuticketweb.ticket.base.UUticketException;
import com.uuticketweb.ticket.flight.bean.Country;
import com.uuticketweb.ticket.flight.bean.FlightInfo;
import com.uuticketweb.ticket.flight.dao.FlightDao;
import com.uuticketweb.ticket.pojos.CompanyTurncity;
import com.uuticketweb.ticket.pojos.PlaneInfo;
import com.uuticketweb.ticket.pojos.ThreeCode;
import com.uuticketweb.ticket.pojos.TwoCode;
import com.uuticketweb.ticket.util.DateHelper;
import com.uuticketweb.ticket.util.MyUtils;

public class FlightService implements InitializingBean {
	protected static Log logger = LogFactory.getLog(FlightService.class);
	
	private FlightDao flightDao;
	
	public void setFlightDao(FlightDao flightDao) {
		this.flightDao = flightDao;
	}
	
	
	
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		// init
	}

	/**
	 * 得到航空公司名以及二字码
	 * @return
	 */
	public List getTwoCode() throws Exception {
		return flightDao.getTwoCode();
	}
	
	public List getAllContinent() throws Exception {
		return flightDao.getAllContinent();
	}
	
	public List getCountryOfContinent(String continent) throws Exception {
		List list = flightDao.getCountryOfContinent(continent);
		List<Country> countryList = new ArrayList<Country>();
		for(int i = 0; i < list.size(); i ++) {
			Object[] ab = (Object[]) list.get(i);
			countryList.add(new Country((String)ab[0], (String)ab[1]));
		}
		return countryList;
	}
	
	public List<Country> getAllCountry() throws Exception {
		List list = flightDao.getAllCountry();
		List<Country> countryList = new ArrayList<Country>();
		for(int i = 0; i < list.size(); i ++) {
			Object[] ab = (Object[])list.get(i);
			countryList.add(new Country((String)ab[0], (String)ab[1]));
		}
		return countryList;
	}
	
	public List getAirportOfCountry(String countryCode) {
		return flightDao.getAirportOfCountry(countryCode);
	}
	
	public TwoCode getCompanyFromTwocode(String twoCode) {
		List list = flightDao.getCompanyFromTwocode(twoCode);
		if(list.isEmpty()) return null;
		return (TwoCode)list.get(0);
	}
	
	private Map<TwoCode, List[]> matchFlight (
			List flightList, 
			String[] departAirport, 
			String[] destAirport, 
			int itineryType, 
			String strToDate,
			String strBackDate,
			String[] companyArr, 
			String[] turncity) throws Exception {
		
		if(flightList == null || flightList.isEmpty()) return null;
		
		Date toDate = DateHelper.parseDate(strToDate);
		Date backDate = null;
		if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
			backDate = DateHelper.parseDate(strBackDate);
		}
		
		Map<TwoCode, List<PlaneInfo>> companyFlightMap = new HashMap<TwoCode, List<PlaneInfo>>();
		if(companyArr == null || companyArr.length > 1) {
			// group the plane info by airline company
			for(int i = 0; i < flightList.size(); i ++) {
				PlaneInfo planeInfo = (PlaneInfo)flightList.get(i);
				TwoCode twoCode = planeInfo.getCarrier();
				List<PlaneInfo> piList = companyFlightMap.get(twoCode);
				if(piList == null) {
					piList = new ArrayList<PlaneInfo>();
				}
				piList.add(planeInfo);
				companyFlightMap.put(twoCode, piList);
			}
		} else {
			// all flights belong to the same company
			companyFlightMap.put(((PlaneInfo)flightList.get(0)).getCarrier(), flightList);
		}
		
		Map<TwoCode, List[]> result = new HashMap<TwoCode, List[]>();
		
		Iterator<Map.Entry<TwoCode, List<PlaneInfo>>> iter = companyFlightMap.entrySet().iterator();
		while(iter.hasNext()) {
			Map.Entry<TwoCode, List<PlaneInfo>> entry = iter.next();
			TwoCode airCom = entry.getKey();
			List<PlaneInfo> piList = entry.getValue();
			
			List<FlightInfo[]> toList = new ArrayList<FlightInfo[]>();
			List<FlightInfo[]> backList = new ArrayList<FlightInfo[]>();
			
			if(turncity == null || turncity.length == 0) {
//				 direct flight
				for(int i = 0; i < piList.size(); i ++) {
					PlaneInfo planeInfo = piList.get(i);
					if(planeInfo.getDeparture() != null && ArrayUtils.contains(departAirport, planeInfo.getDeparture().getAirportThreeCode())) {
						toList.add(new FlightInfo[]{convertToFlightInfo(planeInfo, toDate)});
					}
					else if(itineryType == PlaneInfo.TYPE_ROUND_TRIP && planeInfo.getDeparture() != null && ArrayUtils.contains(destAirport, planeInfo.getDeparture().getAirportThreeCode())) {
						backList.add(new FlightInfo[]{convertToFlightInfo(planeInfo, backDate)});
					}
				}
				
				// TODO: before add to result map judge flight type
				result.put(airCom, new List[]{toList, backList});
			} else {
				// have turncity
				List<PlaneInfo> to1List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> to2List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> back1List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> back2List = new ArrayList<PlaneInfo>();

				for(int i = 0; i < piList.size(); i ++) {
					PlaneInfo planeInfo = piList.get(i);
					if(planeInfo.getDeparture() != null && ArrayUtils.contains(departAirport, planeInfo.getDeparture().getAirportThreeCode()) && 
							planeInfo.getDestination() != null && ArrayUtils.contains(turncity, planeInfo.getDestination().getAirportThreeCode())) {
						to1List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && ArrayUtils.contains(turncity, planeInfo.getDeparture().getAirportThreeCode()) && 
							planeInfo.getDestination() != null && ArrayUtils.contains(destAirport, planeInfo.getDestination().getAirportThreeCode())) {
						to2List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && ArrayUtils.contains(destAirport, planeInfo.getDeparture().getAirportThreeCode()) && 
							planeInfo.getDestination() != null && ArrayUtils.contains(turncity, planeInfo.getDestination().getAirportThreeCode())) {
						back1List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && ArrayUtils.contains(turncity, planeInfo.getDeparture().getAirportThreeCode()) && 
							planeInfo.getDestination() != null && ArrayUtils.contains(departAirport, planeInfo.getDestination().getAirportThreeCode())) {
						back2List.add(planeInfo);
					}
				}
				
				for(int i = 0; i < to1List.size(); i ++) {
					PlaneInfo p1 = to1List.get(i);
					for(int j = 0; j < to2List.size(); j ++) {
						PlaneInfo p2 = to2List.get(j);
						Object rel= concatFlight(p1, p2, toDate);
						if(rel instanceof Boolean && !((Boolean)rel).booleanValue()) continue;
						toList.add((FlightInfo[])rel);
					}
				}

				if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
					for(int i = 0; i < back1List.size(); i ++) {
						PlaneInfo p1 = back1List.get(i);
						for(int j = 0; j < back2List.size(); j ++) {
							PlaneInfo p2 = back2List.get(j);
							Object rel= concatFlight(p1, p2, toDate);
							if(rel instanceof Boolean && !((Boolean)rel).booleanValue()) continue;
							backList.add((FlightInfo[])rel);
						}
					}
				}
			}
		}
		return result;
	}
	
	/**
	 * Match the plane info. 
	 * The conditions
	 * 1. the same airline company.
	 * 2. If has turncity the time staying in city should be longer than 1.5 hour
	 *  but on the same day or continuous two days
	 * @param flightList
	 * @return
	 */
	private Map<TwoCode, List[]> matchFlight (
			List flightList, 
			String departAirport, 
			String destAirport, 
			int itineryType, 
			String strToDate,
			String strBackDate,
			String[] companyArr, 
			String turncity) throws Exception {
		
		if(flightList == null || flightList.isEmpty()) return null;
		
		Date toDate = DateHelper.parseDate(strToDate);
		Date backDate = null;
		if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
			backDate = DateHelper.parseDate(strBackDate);
		}
		
		Map<TwoCode, List<PlaneInfo>> companyFlightMap = new HashMap<TwoCode, List<PlaneInfo>>();
		if(companyArr == null || companyArr.length > 1) {
			// group the plane info by airline company
			for(int i = 0; i < flightList.size(); i ++) {
				PlaneInfo planeInfo = (PlaneInfo)flightList.get(i);
				TwoCode twoCode = planeInfo.getCarrier();
				List<PlaneInfo> piList = companyFlightMap.get(twoCode);
				if(piList == null) {
					piList = new ArrayList<PlaneInfo>();
				}
				piList.add(planeInfo);
				companyFlightMap.put(twoCode, piList);
			}
		} else {
			// all flights belong to the same company
			companyFlightMap.put(((PlaneInfo)flightList.get(0)).getCarrier(), flightList);
		}
		
		Map<TwoCode, List[]> result = new HashMap<TwoCode, List[]>();
		
		Iterator<Map.Entry<TwoCode, List<PlaneInfo>>> iter = companyFlightMap.entrySet().iterator();
		while(iter.hasNext()) {
			Map.Entry<TwoCode, List<PlaneInfo>> entry = iter.next();
			TwoCode airCom = entry.getKey();
			List<PlaneInfo> piList = entry.getValue();
			
			List<FlightInfo[]> toList = new ArrayList<FlightInfo[]>();
			List<FlightInfo[]> backList = new ArrayList<FlightInfo[]>();
			
			if(turncity == null) {
				// direct flight
				for(int i = 0; i < piList.size(); i ++) {
					PlaneInfo planeInfo = piList.get(i);
					if(planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(departAirport)) {
						toList.add(new FlightInfo[]{convertToFlightInfo(planeInfo, toDate)});
					}
					else if(itineryType == PlaneInfo.TYPE_ROUND_TRIP && planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(destAirport)) {
						backList.add(new FlightInfo[]{convertToFlightInfo(planeInfo, backDate)});
					}
				}
				
				// TODO: before add to result map judge flight type
				result.put(airCom, new List[]{toList, backList});
			} else {
				// have turncity
				List<PlaneInfo> to1List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> to2List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> back1List = new ArrayList<PlaneInfo>();
				List<PlaneInfo> back2List = new ArrayList<PlaneInfo>();

				for(int i = 0; i < piList.size(); i ++) {
					PlaneInfo planeInfo = piList.get(i);
					if(planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(departAirport) && 
							planeInfo.getDestination() != null && planeInfo.getDestination().getAirportThreeCode().equals(turncity)) {
						to1List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(turncity) && 
							planeInfo.getDestination() != null && planeInfo.getDestination().getAirportThreeCode().equals(destAirport)) {
						to2List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(destAirport) && 
							planeInfo.getDestination() != null && planeInfo.getDestination().getAirportThreeCode().equals(turncity)) {
						back1List.add(planeInfo);
					}
					else if(planeInfo.getDeparture() != null && planeInfo.getDeparture().getAirportThreeCode().equals(turncity) && 
							planeInfo.getDestination() != null && planeInfo.getDestination().getAirportThreeCode().equals(departAirport)) {
						back2List.add(planeInfo);
					}
				}
				
				// TODO: before process need judge flight type
				
				for(int i = 0; i < to1List.size(); i ++) {
					PlaneInfo p1 = to1List.get(i);
					for(int j = 0; j < to2List.size(); j ++) {
						PlaneInfo p2 = to2List.get(j);
						Object rel= concatFlight(p1, p2, toDate);
						if(rel instanceof Boolean && !((Boolean)rel).booleanValue()) continue;
						toList.add((FlightInfo[])rel);
					}
				}

				if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
					for(int i = 0; i < back1List.size(); i ++) {
						PlaneInfo p1 = back1List.get(i);
						for(int j = 0; j < back2List.size(); j ++) {
							PlaneInfo p2 = back2List.get(j);
							Object rel= concatFlight(p1, p2, toDate);
							if(rel instanceof Boolean && !((Boolean)rel).booleanValue()) continue;
							backList.add((FlightInfo[])rel);
						}
					}
				}
				
			}
		}
		return result;
	}
	
	/**
	 * 
	 * @param firstPlaneInfo The flight from departure to turn city
	 * @param secondPlaneInfo The flight from turn city to destination
	 * @param startDate The start date
	 * @return
	 */
	private Object concatFlight(PlaneInfo firstPlaneInfo, PlaneInfo secondPlaneInfo, Date toDate) {
		if(!firstPlaneInfo.getYear().equals(secondPlaneInfo.getYear()) || 
				!firstPlaneInfo.getSeason().equals(secondPlaneInfo.getSeason()) ||
				!firstPlaneInfo.getCarrier().equals(secondPlaneInfo.getCarrier()) || 
				!firstPlaneInfo.getDestination().getAirportThreeCode().equals(secondPlaneInfo.getDeparture().getAirportThreeCode())) {
			return Boolean.FALSE;
		}
		
		FlightInfo firstFlightInfo = fillFlightDays(firstPlaneInfo);
		FlightInfo secondFlightInfo = fillFlightDays(secondPlaneInfo);
		
		for(int i = 0; i < firstFlightInfo.getAvaiableDays().length;  i ++) {
			// no flight on the day
			if(!firstFlightInfo.getAvaiableDays()[i]) continue;
			
			// on the same same day
			if(secondFlightInfo.getAvaiableDays()[(i + firstFlightInfo.getAddDays()) % 7]) {
				// the gap is 1 hour and 30 min
				if(getTimeGap(secondFlightInfo.getTakeOffTime(), firstFlightInfo.getPutDownTime()) >= 130) {
					firstFlightInfo.setTakeoffDate(toDate);
					firstFlightInfo.setPutdownDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays()));
					secondFlightInfo.setTakeoffDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays()));
					secondFlightInfo.setPutdownDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays() + secondFlightInfo.getAddDays()));
					return new FlightInfo[]{firstFlightInfo, secondFlightInfo};
				}
			}
			// on the second day
			else if(secondFlightInfo.getAvaiableDays()[(i + 1 + firstFlightInfo.getAddDays()) % 7]) {
				firstFlightInfo.setTakeoffDate(toDate);
				firstFlightInfo.setPutdownDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays()));
				secondFlightInfo.setTakeoffDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays() + 1));
				secondFlightInfo.setPutdownDate(DateHelper.addDays(toDate, firstFlightInfo.getAddDays() + secondFlightInfo.getAddDays() + 1));
				return new FlightInfo[]{firstFlightInfo, secondFlightInfo};
			}
		}
		
		return Boolean.FALSE;
	}
	
	/**
	 * Compute the gap of two time. 
	 * Eg. time1 = 1030 time2 = 1220, result = 150
	 * @return
	 */
	private int getTimeGap(int time1, int time2) {
		return time2 - time1 - 40;
	}
	
	private FlightInfo fillFlightDays(PlaneInfo planeInfo) {
		FlightInfo flightInfo = new FlightInfo(planeInfo);
		boolean[] avaiableDays = new boolean[7];
		if(planeInfo.getDay1().equals("Y")) avaiableDays[0] = true;
		if(planeInfo.getDay2().equals("Y")) avaiableDays[1] = true;
		if(planeInfo.getDay3().equals("Y")) avaiableDays[2] = true;
		if(planeInfo.getDay4().equals("Y")) avaiableDays[3] = true;
		if(planeInfo.getDay5().equals("Y")) avaiableDays[4] = true;
		if(planeInfo.getDay6().equals("Y")) avaiableDays[5] = true;
		if(planeInfo.getDay7().equals("Y")) avaiableDays[6] = true;
		flightInfo.setAvaiableDays(avaiableDays);
		
		String putdownTime = planeInfo.getPutdowntime();
		int addDays = 0;
		int pos = putdownTime.indexOf("+");
		if(pos != -1) {
			addDays = Integer.parseInt(putdownTime.substring(pos + 1));
			putdownTime = putdownTime.substring(0, pos);
		}
		flightInfo.setPutDownTime(Integer.parseInt(putdownTime));
		flightInfo.setTakeOffTime(Integer.parseInt(planeInfo.getTakeofftime()));
		flightInfo.setAddDays(addDays);
		return flightInfo;
	}
	
	private FlightInfo convertToFlightInfo(PlaneInfo planeInfo, Date toDate) {
		FlightInfo flightInfo = fillFlightDays(planeInfo);
		flightInfo.setTakeoffDate(toDate);
		flightInfo.setPutdownDate(DateHelper.addDays(toDate, flightInfo.getAddDays()));
		return flightInfo;
	}
	
	private String[] moveElementArray(String[] strArr, int mPos) {
		if(strArr == null || strArr.length == 0 || mPos == 0) return strArr;
		mPos = mPos % strArr.length;
		
		return (String[])ArrayUtils.addAll(ArrayUtils.subarray(strArr, mPos, strArr.length), ArrayUtils.subarray(strArr, 0, mPos));
	}
	
	/**
	 * Retrive the Flight info from depart airport and dest airport. 
	 * Also search the flight either depart airport and dest airport are 
	 * in the same city with the airports searched.
	 * @param singleDepartAirport The three code of the depart airport
	 * @param singleDestAirport The three code of the dest airport
	 * @param strItineryType iternery type. If equals to '0' one way otherwise round trip
	 * @param toDate The depart date. format is 'yyyy-MM-dd'
	 * @param backDate The arrival daet, format is 'yyyy-MM-dd'
	 * @param company The two code of airline. Can be null which means search all the air company
	 * @param turncity The three code of transfer city. Can be null which means direct trip
	 * @return A map with key is the TwoCode which represent airline company and with value is
	 *  list of com.uuticketweb.ticket.flight.bean.FlightInfo. FlightInfo is a bean exist for 
	 *  display search result in front pages. 
	 * @throws Exception
	 */
	public Map<TwoCode, List[]> getFullFlightList(
			String singleDepartAirport,
			String singleDestAirport,
			String strItineryType, 
            String toDate,
            String backDate,
            String company,
            String turncity) throws Exception {
		
		int itineryType = PlaneInfo.TYPE_ROUND_TRIP;
		if(strItineryType.equals("0")) {
			itineryType = PlaneInfo.TYPE_ONE_WAY;
		}
		
		String[] companyArr = null;
		if(!StringUtils.isBlank(company) && !company.equals(TwoCode.ALL_TWO_CODE)) {
			companyArr = new String[]{company};
			if("KA".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "CX");
			}
			if("CX".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "KA");
			}
			if("AF".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "KL");
			}
			if("KL".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "AF");
			}
		}
		
		String[] turncityAirport = null;
		if(StringUtils.isBlank(turncity) || turncity.equals("00")) {
			turncityAirport = null;
		}
		
		
		String toSeason = DateHelper.getSeason(toDate);
		String toDay = DateHelper.getDay(toDate);
		String toYear = DateHelper.getYear(toDate);
		
		String[] toTransferYear = new String[]{toYear};
		String[] toTransferSeason = new String[]{toSeason};
		String[] toTransferDay = new String[]{toDay};
		
		String backSeason, backDay, backYear;
		backSeason = backDay = backYear = null;
		String[] backTransferYear, backTransferSeason, backTransferDay;
		backTransferYear = backTransferSeason = backTransferDay = null;

		if(!StringUtils.isBlank(backDate)) {
			backSeason = DateHelper.getSeason(backDate);
			backDay = DateHelper.getDay(backDate);
			backYear = DateHelper.getYear(backDate);

			backTransferYear = new String[]{backYear};
			backTransferSeason = new String[]{backSeason};
			backTransferDay = new String[]{backDay};
		}

		if(turncity != null) {
			int i =  DateHelper.isDateCrossSeasonOrYear(toDate);
			if(i == 1) {
				// cross year
				toTransferYear = (String[])ArrayUtils.add(toTransferYear, String.valueOf(Integer.parseInt(toYear) + 1));
				toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, "1");
				toTransferDay = getPossibleDay(toDay);
			} else if(i == 2) {
				// cross season
				toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, String.valueOf(Integer.parseInt(toSeason) + 1));
				toTransferDay = getPossibleDay(toDay);
			}
			
			if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
				i = DateHelper.isDateCrossSeasonOrYear(backDate);
				if(i == 1) {
					// cross year
					backTransferYear = (String[])ArrayUtils.add(backTransferYear, String.valueOf(Integer.parseInt(backYear) + 1));
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, "1");
					backTransferDay = getPossibleDay(backDay);
				} else if(i == 2) {
					// cross season
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, String.valueOf(Integer.parseInt(backSeason) + 1));
					backTransferDay = getPossibleDay(backDay);
				}
			}
		}
		
		List departAirportList = flightDao.getAirportsCodeInSameCity(singleDepartAirport);
		String[] departAirport = MyUtils.listToArray(departAirportList);
		if(departAirport == null) {
			departAirport = new String[]{singleDepartAirport};
		}
		List destAirportList = flightDao.getAirportsCodeInSameCity(singleDestAirport);
		String[] destAirport = MyUtils.listToArray(destAirportList);
		if(destAirport == null) {
			destAirport = new String[]{singleDestAirport};
		}
		List flightList = flightDao.getFlightList(departAirport, destAirport, turncityAirport, 
				toYear, toTransferYear, toSeason, toTransferSeason, toDay, toTransferDay, 
				backYear, backTransferYear, backSeason, backTransferSeason, backDay, backTransferDay, 
				itineryType, companyArr);
		
		return matchFlight(flightList, departAirport, destAirport, itineryType, toDate, backDate, companyArr, turncityAirport);
	}
	
	/**
	 * 根据用户的查询条件，从数据库中查询出航班
	 * 
	 * @param departAirport
	 * @param backDate The back date. Just use it to decide itinery type
	 * @return
	 */
	public Map<TwoCode, List[]> getFlightList(
			String departAirport,
			String destAirport,
			String strItineryType, 
            String toDate,
            String backDate,
            String company,
            String turncity) throws Exception {
		
		int itineryType = PlaneInfo.TYPE_ROUND_TRIP;
		if(strItineryType.equals("0")) {
			itineryType = PlaneInfo.TYPE_ONE_WAY;
		}
		
		String[] companyArr = null;
		if(!StringUtils.isBlank(company) && !company.equals(TwoCode.ALL_TWO_CODE)) {
			companyArr = new String[]{company};
			if("KA".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "CX");
			}
			if("CX".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "KA");
			}
			if("AF".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "KL");
			}
			if("KL".equals(company)) {
				companyArr = (String[])ArrayUtils.add(companyArr, "AF");
			}
		}
		
		if(StringUtils.isBlank(turncity) || turncity.equals("00")) {
			turncity = null;
		}
		
		String toSeason = DateHelper.getSeason(toDate);
		String toDay = DateHelper.getDay(toDate);
		String toYear = DateHelper.getYear(toDate);
		
		String[] toTransferYear = new String[]{toYear};
		String[] toTransferSeason = new String[]{toSeason};
		String[] toTransferDay = new String[]{toDay};
		
		String backSeason, backDay, backYear;
		backSeason = backDay = backYear = null;
		String[] backTransferYear, backTransferSeason, backTransferDay;
		backTransferYear = backTransferSeason = backTransferDay = null;

		if(!StringUtils.isBlank(backDate)) {
			backSeason = DateHelper.getSeason(backDate);
			backDay = DateHelper.getDay(backDate);
			backYear = DateHelper.getYear(backDate);

			backTransferYear = new String[]{backYear};
			backTransferSeason = new String[]{backSeason};
			backTransferDay = new String[]{backDay};
		}

		if(turncity != null) {
			int i =  DateHelper.isDateCrossSeasonOrYear(toDate);
			if(i == 1) {
				// cross year
				toTransferYear = (String[])ArrayUtils.add(toTransferYear, String.valueOf(Integer.parseInt(toYear) + 1));
				toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, "1");
				toTransferDay = getPossibleDay(toDay);
			} else if(i == 2) {
				// cross season
				toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, String.valueOf(Integer.parseInt(toSeason) + 1));
				toTransferDay = getPossibleDay(toDay);
			}
			
			if(itineryType == PlaneInfo.TYPE_ROUND_TRIP) {
				i = DateHelper.isDateCrossSeasonOrYear(backDate);
				if(i == 1) {
					// cross year
					backTransferYear = (String[])ArrayUtils.add(backTransferYear, String.valueOf(Integer.parseInt(backYear) + 1));
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, "1");
					backTransferDay = getPossibleDay(backDay);
				} else if(i == 2) {
					// cross season
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, String.valueOf(Integer.parseInt(backSeason) + 1));
					backTransferDay = getPossibleDay(backDay);
				}
			}
		}
		
		/*if(itineryType == PlaneInfo.TYPE_ONE_WAY) {
			if(turncity != null) {
				int i =  DateHelper.isDateCrossSeasonOrYear(toDate);
				if(i == 1) {
					// cross year
					toTransferYear = (String[])ArrayUtils.add(toTransferYear, String.valueOf(Integer.parseInt(toYear) + 1));
					toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, "1");
					toTransferDay = getPossibleDay(toDay);
				} else if(i == 2) {
					// cross season
					toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, String.valueOf(Integer.parseInt(toSeason) + 1));
					toTransferDay = getPossibleDay(toDay);
				}
			}
		} else {
			if(turncity != null) {
				int i = DateHelper.isDateCrossSeasonOrYear(toDate);
				if(i == 1) {
					// cross year
					toTransferYear = (String[])ArrayUtils.add(toTransferYear, String.valueOf(Integer.parseInt(toYear) + 1));
					toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, "1");
					toTransferDay = getPossibleDay(toDay);
				} else if(i == 2) {
					// cross season
					toTransferSeason = (String[])ArrayUtils.add(toTransferSeason, String.valueOf(Integer.parseInt(toSeason) + 1));
					toTransferDay = getPossibleDay(toDay);
				}
				
				i = DateHelper.isDateCrossSeasonOrYear(backDate);
				if(i == 1) {
					// cross year
					backTransferYear = (String[])ArrayUtils.add(backTransferYear, String.valueOf(Integer.parseInt(backYear) + 1));
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, "1");
					backTransferDay = getPossibleDay(backDay);
				} else if(i == 2) {
					// cross season
					backTransferSeason = (String[])ArrayUtils.add(backTransferSeason, String.valueOf(Integer.parseInt(backSeason) + 1));
					backTransferDay = getPossibleDay(backDay);
				}
			}
		}*/
		
		
		List flightList = flightDao.getFlightList(departAirport, destAirport, turncity, 
				toYear, toTransferYear, toSeason, toTransferSeason, toDay, toTransferDay, 
				backYear, backTransferYear, backSeason, backTransferSeason, backDay, backTransferDay, 
				itineryType, companyArr);
		
		return matchFlight(flightList, departAirport, destAirport, itineryType, toDate, backDate, companyArr, turncity);
	}
	
	private String[] getPossibleDay(String day) {
		int i = Integer.parseInt(day);
		String[] da = new String[3];
		for(int j = 0; j < 3; j ++) {
			da[j] = String.valueOf((j + i) % 7);
		}
		return da;
	}
	
	/**
	 * 格式化起飞时间
	 * @param time
	 * @return
	 */
	private String getTime(String time){
		return time.substring(0,2)+time.substring(time.length()-2,time.length());
	}
	
	public PlaneInfo getPlaneInfo(String planeInfoId) throws UUticketException {
		return flightDao.getPlaneInfo(planeInfoId);
	}
	
	public CompanyTurncity getTransAirportOfCompany(String companyTwoCode) {
		List list = flightDao.getTransAirportOfCompany(companyTwoCode);
		if(list.isEmpty()) return null;
		return (CompanyTurncity)list.get(0);
	}
	
	public CompanyTurncity getCompanyOfTransAirport(String airportThreeCode) {
		List list = flightDao.getCompanyOfTransAirport(airportThreeCode);
		if(list.isEmpty()) return null;
		return (CompanyTurncity)list.get(0);
	}
	
	public List getAllTurncity() {
		return flightDao.getAllTurncity();
	}
	
	public List getDistinctTurncityThreecode() {
		return flightDao.getDistinctTurncityThreecode();
		// oracle 8i does not support the join sql statement
		/*
		List list = flightDao.getAllTurncity();
		List result = new ArrayList();
		String buf = null;
		for(int i = 0; i < list.size(); i ++) {
			CompanyTurncity ct = (CompanyTurncity)list.get(i);
			if(ct != null) {
				String str = ct.getTurnCityThreeCode().getAirportThreeCode();
				if(!str.equals(buf)) {
					result.add(ct.getTurnCityThreeCode());
					buf = str;
				}
			}
		}
		return result;
		*/
	}
	
	public ThreeCode getAirportByThreeCode(String threeCode) {
		List list = flightDao.getAirportByThreeCode(threeCode);
		if(list.isEmpty()) return null;
		return (ThreeCode)list.get(0);
	}
	
	public List queryThreecodeByStart(String str) {
		List list = flightDao.queryThreecodeByStart(str);
		return list;
	}
}
